package cn.seaboot.admin.security.auth;

import cn.seaboot.admin.security.login.*;
import cn.seaboot.admin.security.token.TokenFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.annotation.Resource;

/**
 * Security configuration
 *
 * @author Mr.css
 * @version 2020-05-07 23:38
 */
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    private Logger logger = LoggerFactory.getLogger(SecurityConfiguration.class);

    @Resource
    private CustomUserDetailsService userDetailsService;

    @Resource
    private PasswordHelper passwordHelper;

    @Resource
    private LoginFailureHandler loginFailureHandler;

    @Resource
    private LoginSuccessHandler loginSuccessHandler;

    @Resource
    private TokenFilter tokenFilter;

    @Resource
    private CustomAuthenticationProvider authenticationProvider;

    @Resource
    private AntAuthorityAccessDecision antAuthorityAccessDecision;

    /**
     * 这个类继承自 InitializingBean 的类，添加到 spring 容器是会报错的
     */
    private final LoginFilter loginFilter = new LoginFilter();

    /**
     * HttpSecurity相关配置
     *
     * @param http HttpSecurity
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 投票规则
        http.authorizeRequests().accessDecisionManager(antAuthorityAccessDecision).anyRequest().authenticated();

        // 鉴权管理
        loginFilter.setAuthenticationManager(super.authenticationManager());

        // failure callback
        loginFilter.setAuthenticationFailureHandler(loginFailureHandler);

        // success callback
        loginFilter.setAuthenticationSuccessHandler(loginSuccessHandler);

        // check setting
        loginFilter.afterPropertiesSet();

        // 添加拦截器
        http.addFilterAt(loginFilter, UsernamePasswordAuthenticationFilter.class)
                .addFilterAfter(tokenFilter, LoginFilter.class);

        // 基于 token，所以不需要 session
        // http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        // 禁用 CSRF，默认用于防止 CSRF 攻击的设置，模版引擎中使用
        // 这个配置，也会影响到 GET 之外的提交方式
        http.csrf().disable();

        // 未登录认证异常
        // http.exceptionHandling().authenticationEntryPoint()

        // 登录之后无权限处理，403 状态
        // http.exceptionHandling().accessDeniedHandler()

        // 这个配置能让 IFrame 无法嵌套我们的页面，可以防止盗链，
        // http.headers().frameOptions().disable();
    }

    /**
     * 用户鉴权相关
     * <p>
     * 用户信息查询、密码加密等功能
     *
     * @param auth AuthenticationManagerBuilder
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) {
        authenticationProvider.setUserDetailsService(userDetailsService);
        authenticationProvider.setPasswordEncoder(passwordHelper);
        auth.authenticationProvider(authenticationProvider);
    }
}
